<template>
	<div ref="chatContainer" class="chat-container">
		<!-- 顶部 固定 -->
		<div class="chat-header row-ac">
			<div style="margin-left: 1rem;">
				<i class="iconfont icon-back2-01"></i>
				<span class="font-s-15">{{ languageType === 'English' ? 'Back' : 'Geri' }}</span>
			</div>
		</div>

		<div class="w-100" style="height: 60px;"></div>

		<div ref="chatContent" class="chat-content" @scroll="onScroll">
			<div v-for="(item, index) in messages" :key="item.id || index"
				:class="['msg-row', item.is_initiate ? 'msg-right' : '']">
				<img v-if="!item.is_initiate" src="https://i.pravatar.cc/40?img=68" class="avatar avatar-right" />
				<div :class="['msg-bubble', item.is_initiate ? 'msg-right-bubble' : 'msg-left']">
					<div class="msg-content" v-if="!item.content_img">{{ item.content }}</div>
					<img v-else :src="item.content_img" class="msg-img" @load="onImageLoad"
						@click="previewImage(item.content_img)" />
				</div>
				<img v-if="item.is_initiate" src="https://i.pravatar.cc/40?img=12" class="avatar avatar-left" />
			</div>
		</div>

		<div class="w-100" style="height: 75px;"></div>

		<div ref="inputBar" class="input-bar row-ac">
			<textarea ref="textareaRef" v-model="messageText" placeholder="Type your message..." @input="autoResize"
				@keyup.enter="sendTextMessageEnter" @focus="onInputFocus"></textarea>
			<button class="btn-send"
				@click="sendTextMessage">{{ languageType === 'English' ? 'Send' : 'Gönder' }}</button>
		</div>

		<div v-if="previewVisible" class="preview-mask" @click="previewVisible = false">
			<img :src="previewUrl" class="preview-img" />
		</div>
	</div>
</template>

<script setup lang="ts">
	import { ref, nextTick, onMounted, onBeforeUnmount, computed } from 'vue'
	import { useRoute } from 'vue-router'

	const { post } = useFetchApi()
	const route = useRoute()

	const messages = ref<any[]>([])
	const chatContent = ref<HTMLElement | null>(null)
	const textareaRef = ref<HTMLTextAreaElement | null>(null)
	const languageType = ref('English')

	const previewVisible = ref(false)
	const previewUrl = ref('')
	const sessionId = ref('')
	const messageText = ref('')
	const autoScroll = ref(true)
	let ws : WebSocket | null = null
	let reconnectAttempts = 0
	const maxReconnects = 5

	let currentPage = 1
	const pageSize = 20
	let totalPages = 1
	let loadingPrev = false

	// ---------- 状态 ----------
	const connectionStatus = ref<'connecting' | 'open' | 'closed'>('connecting')
	const connectionStatusText = computed(() => {
		switch (connectionStatus.value) {
			case 'connecting':
				return '连接中...'
			case 'open':
				return '已连接'
			default:
				return '已断开'
		}
	})
	const connectionStatusClass = computed(() => ({
		connecting: connectionStatus.value === 'connecting',
		open: connectionStatus.value === 'open',
		closed: connectionStatus.value === 'closed',
	}))

	// ---------- WebSocket ----------
	const connectWebSocket = () => {
		if (!sessionId.value) return
		const wsUrl = `ws://bet.dreammirac.com/api/ws/chat/${sessionId.value}`
		connectionStatus.value = 'connecting'

		ws = new WebSocket(wsUrl)

		ws.onopen = () => {
			connectionStatus.value = 'open'
			reconnectAttempts = 0
		}

		ws.onmessage = async (ev) => {
			try {
				const data = JSON.parse(ev.data)
				const list = data.data?.list || []
				const action = data.data?.action

				if (action === 'new') {
					messages.value.push(...list)
					await scrollAfterRender()
				} else if (action === 'prev') {
					if (!chatContent.value) {
						messages.value = [...list, ...messages.value]
					} else {
						const prevScrollHeight = chatContent.value.scrollHeight
						messages.value = [...list, ...messages.value]
						await nextTick()
						chatContent.value.scrollTop = chatContent.value.scrollHeight - prevScrollHeight
					}
				} else if (action === 'init') {
					messages.value = list
					totalPages = data.data?.total_pages || 1
					currentPage = data.data?.page || 1
					await scrollAfterRender()
				}
			} catch (e) {
				console.error('消息解析错误:', e)
			}
		}

		ws.onclose = () => {
			connectionStatus.value = 'closed'
			reconnect()
		}

		ws.onerror = (err) => {
			console.error('WebSocket 错误:', err)
			connectionStatus.value = 'closed'
			reconnect()
		}
	}

	const reconnect = () => {
		if (reconnectAttempts >= maxReconnects) return
		reconnectAttempts++
		connectionStatus.value = 'connecting'
		setTimeout(connectWebSocket, reconnectAttempts * 1000)
	}

	// ---------- 滚动 ----------
	const scrollToBottom = () => {
		if (!chatContent.value) return
		chatContent.value.scrollTop = chatContent.value.scrollHeight
	}

	// ⚙️ 等待渲染完后滚动（防止停在中间）
	const scrollAfterRender = async () => {
		await nextTick()
		requestAnimationFrame(() => {
			setTimeout(() => {
				if (autoScroll.value) scrollToBottom()
			}, 60)
		})
	}

	// 图片加载后再滚动一次，防止推高消息区
	const onImageLoad = () => {
		if (autoScroll.value) scrollAfterRender()
	}

	const onScroll = async () => {
		if (!chatContent.value) return
		const { scrollTop, clientHeight, scrollHeight } = chatContent.value
		autoScroll.value = scrollTop + clientHeight >= scrollHeight - 100

		if (scrollTop <= 60 && !loadingPrev && currentPage < totalPages && ws && ws.readyState === WebSocket.OPEN) {
			loadingPrev = true
			const nextPage = currentPage + 1
			try {
				ws.send(JSON.stringify({ action: 'prev', page: nextPage, page_size: pageSize }))
				currentPage = nextPage
			} catch (e) {
				console.error('请求历史失败', e)
			} finally {
				setTimeout(() => (loadingPrev = false), 400)
			}
		}
	}

	// ---------- 输入 ----------
	const autoResize = () => {
		if (!textareaRef.value) return
		const el = textareaRef.value
		el.style.height = 'auto'
		el.style.height = Math.min(el.scrollHeight, 38) + 'px'
		if (autoScroll.value) scrollAfterRender()
	}

	const resetTextarea = () => {
		if (textareaRef.value) textareaRef.value.style.height = '22px'
	}

	const onInputFocus = () => {
		setTimeout(() => scrollAfterRender(), 300)
	}

	const sendTextMessage = async () => {
		if (!messageText.value.trim()) return
		try {
			await post('/api/chat/create_messages', {
				session_id: sessionId.value,
				content: messageText.value,
				content_img: '',
			})
		} catch (err) {
			console.error('发送失败:', err)
		}
		messageText.value = ''
		resetTextarea()
	}

	const sendTextMessageEnter = (e : KeyboardEvent) => {
		if (e.shiftKey) return
		e.preventDefault()
		sendTextMessage()
	}

	const previewImage = (url : string) => {
		previewUrl.value = url
		previewVisible.value = true
	}

	// ---------- 生命周期 ----------
	onMounted(async () => {
		const savedLang = localStorage.getItem('languageType')
		if (savedLang) languageType.value = savedLang
		sessionId.value = route.params.sessionId as string
		connectWebSocket()
		await scrollAfterRender()

		if (typeof window !== 'undefined') {
			const handleResize = () => {
				if (autoScroll.value) scrollAfterRender()
			}
			window.addEventListener('resize', handleResize)
			window.visualViewport?.addEventListener('resize', handleResize)
		}
	})

	onBeforeUnmount(() => {
		if (ws) ws.close()
	})
</script>

<style scoped>
	.chat-container {
		font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif !important;
		display: flex;
		flex-direction: column;
		height: 100vh;
		background: #f5f5f5;
		overflow: hidden;
	}

	.chat-header {
		position: fixed;
		top: 0;
		left: 0;
		width: 100%;
		height: 60px;
		color: #fff;
		box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
		z-index: 10;
		background: linear-gradient(135deg, #030d26 0%, #1a2a4a 100%);
	}

	.status {
		font-size: 12px;
	}

	.status.connecting {
		color: #f59e0b;
	}

	.status.open {
		color: #10b981;
	}

	.status.closed {
		color: #ef4444;
	}

	.chat-content {
		flex: 1;
		overflow-y: auto;
		padding: 70px 10px 90px;
		box-sizing: border-box;
		background-color: #fff;
		-webkit-overflow-scrolling: touch;
	}

	.msg-row {
		display: flex;
		align-items: flex-start;
		margin-bottom: 1rem;
	}

	.msg-right {
		justify-content: flex-end;
	}

	.avatar {
		width: 40px;
		height: 40px;
		border-radius: 50%;
	}

	.avatar-left {
		margin-left: 0.4rem;
	}

	.avatar-right {
		margin-right: 0.4rem;
	}

	.msg-bubble {
		max-width: 70%;
		padding: 0.6rem 0.8rem;
		border-radius: 4px;
		word-break: break-word;
		box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
	}

	.msg-left {
		background: #f5f5f5;
	}

	.msg-right-bubble {
		background: #4d96e2;
	}

	.msg-content {
		font-size: 1.1rem;
	}

	.msg-img {
		max-width: 12rem;
		max-height: 12rem;
		border-radius: 8px;
		margin-top: 0.25rem;
		cursor: pointer;
	}

	.input-bar {
		position: fixed;
		bottom: 0;
		left: 0;
		width: 100%;
		height: 75px;
		background: #fff;
		border-top: 1px solid #eee;
		box-sizing: border-box;
	}

	textarea {
		flex: 1;
		height: 22px;
		padding: 0.5rem;
		border-radius: 4px;
		border: 1px solid #ccc;
		resize: none;
		outline: none;
		line-height: 1.5;
		font-size: 16px;
		color: #333;
		margin-left: 1rem;
	}

	.btn-send {
		margin-left: 0.5rem;
		margin-right: 1rem;
		padding: 0.6rem 1rem;
		border-radius: 4px;
		border: none;
		color: #fff;
		font-size: 16px;
		background: rgba(0, 0, 0, 0.9);
	}

	.preview-mask {
		position: fixed;
		inset: 0;
		background: rgba(0, 0, 0, 0.9);
		display: flex;
		align-items: center;
		justify-content: center;
		z-index: 50;
	}

	.preview-img {
		max-width: 90%;
		max-height: 90%;
		border-radius: 8px;
	}
</style>